package com.a0soft.gphone.aTruffleHog.di;
/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * Copyright(C) 2011 
 *   Sam Lu <ysl.sam.lu (at) gmail.com>
 *
 */

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.json.JSONArray;

import android.hardware.Camera;
import android.hardware.Camera.Size;

import com.a0soft.gphone.aTruffleHog.util.CONSTS;
import com.a0soft.gphone.aTruffleHog.util.MiscUtil;
import com.a0soft.gphone.aTruffleHog.util.SDK11;
import com.a0soft.gphone.aTruffleHog.util.SDK8;
import com.a0soft.gphone.aTruffleHog.util.SDK9;

class CameraInfo extends BaseInfo {  
    private static final int FACING_BACK = 0; //android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK
    //private static final int FACING_FRONT = 1; //android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT
	//private static final String LOG_TAG = CameraInfo.class.getSimpleName();
	
	static void
    Build(DeviceInfo di)
    {
        int nCameraNum;
        int nBackCameraID = -1, nFrontCameraID = -1;
        Camera camera = null;
		if (MiscUtil.GetSDKVersion() >= 9) {
		    SDK9 sdk9 = SDK9.GetInstance();
		    nCameraNum = sdk9.Camera_GetNumberOfCameras();
		    if (nCameraNum >= 1) {
		        if (sdk9.Camera_GetFacingType(0) == FACING_BACK)
		            nBackCameraID = 0;
		        else
		            nFrontCameraID = 0;
		    }
		    if (nCameraNum >= 2) {
                if (sdk9.Camera_GetFacingType(1) == FACING_BACK)
                    nBackCameraID = 1;
                else
                    nFrontCameraID = 1;
            }
		    if (nBackCameraID >= 0)
		        camera = sdk9.Camera_Open(nBackCameraID);
		}
		else {
		    try {
		        camera = Camera.open();
		    } catch (Exception e) {
		        camera = null;
		    }
		    if (camera != null) {
		        nCameraNum = 1;
		        nBackCameraID = 0;
		    }
		    else
		        nCameraNum = 0;
		}
		
        di.Put(DeviceInfoKey.K.CA_NUMBER, nCameraNum);
        
        ////////////////////////////////////////////////
        //0:back camera, 1:front camera
        ////////////////////////////////////////////////
        if (MiscUtil.GetSDKVersion() >= 9) {
            SDK9 sdk9 = SDK9.GetInstance();
            Integer[] nFacingTypes = new Integer[nCameraNum];
            Integer[] nOrientations = new Integer[nCameraNum];
            if (nBackCameraID >= 0) {
                nFacingTypes[nBackCameraID] = sdk9.Camera_GetFacingType(nBackCameraID);
                nOrientations[nBackCameraID] = sdk9.Camera_GetOrientation(nBackCameraID);
            }
            if (nFrontCameraID >= 0) {
                nFacingTypes[nFrontCameraID] = sdk9.Camera_GetFacingType(nFrontCameraID);
                nOrientations[nFrontCameraID] = sdk9.Camera_GetOrientation(nFrontCameraID);
            }
            di.Put(DeviceInfoKey.K.CA_FACING, Arrays.asList(nFacingTypes));
            di.Put(DeviceInfoKey.K.CA_ORIENTATION, Arrays.asList(nOrientations));
        }
        else {
            di.Put(DeviceInfoKey.K.CA_FACING, CONSTS.UNAVAILABLE);
            di.Put(DeviceInfoKey.K.CA_ORIENTATION, CONSTS.UNAVAILABLE);
        }
        
        Camera.Parameters[] params = new Camera.Parameters[]{null, null};
        if (camera != null) {
            params[0] = camera.getParameters();
            try {
                camera.release();                
            } catch (Exception e) {}
            camera = null;
        }
        if (MiscUtil.GetSDKVersion() >= 9 && nFrontCameraID >= 0) {
            camera = SDK9.GetInstance().Camera_Open(nFrontCameraID);
            if (camera != null) {
                params[1] = camera.getParameters();
                try {
                    camera.release();                
                } catch (Exception e) {}
                camera = null;
            }
        }
        
        _PicFormat(di, params);
        _PicSize(di, params);
        
        _PreviewFormat(di, params);
        _PreviewSize(di, params);
        _PreviewFrameRate(di, params);
        _PreviewFPS(di, params);
        
        _VideoSize(di, params);
        
        _ThumbnailSize(di, params);
        
        _Zoom(di, params);
        
        _Others(di, params);
    }
	
	private static void
	_PicFormat(DeviceInfo di, Camera.Parameters[] params)
	{
	    //[[format1,format2],"unavailable"]
	    ArrayList<Object> objs = new ArrayList<Object>(params.length);
	    for (Camera.Parameters param: params) {
    	    if (param == null) {
    	        objs.add(CONSTS.UNAVAILABLE);
    	        continue;
    	    }
    	    
    	    List<Integer> formats;
    	    try {
    	        formats = param.getSupportedPictureFormats();            
    	    } catch (Exception e) { //java.lang.NullPointerException on emulator
    	        formats = null;
    	    }
    	    
            if (formats == null)
                objs.add(CONSTS.UNAVAILABLE);
            else {
                JSONArray array = new JSONArray(formats);
                objs.add(array);
            }
	    }
	    di.Put(DeviceInfoKey.K.CA_PIC_FMT, objs);
	}
	
	private static void
    _PicSize(DeviceInfo di, Camera.Parameters[] params)
    {
        ArrayList<Object> objs = new ArrayList<Object>(params.length);
        List<Size> sizes;
        
        //picture size
        //[[[w1,h1],[w2,h2]],"unavailable"]
        objs.clear();
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }

            sizes = param.getSupportedPictureSizes();
            if (sizes == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }

            JSONArray array = new JSONArray();
            for (Size size: sizes) {
                array.put(new JSONArray().put(size.width).put(size.height));
            }
            objs.add(array);
        }
        di.Put(DeviceInfoKey.K.CA_PIC_SIZE, objs);
        
        //pixels
        //[pixels1,"unavailable"]
        objs.clear();
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }
            
            long lMaxPixels = Long.MIN_VALUE, lPixels;            
            sizes = param.getSupportedPictureSizes();
            if (sizes == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }
            
            for (Size size: sizes) {
                lPixels = size.width * (long)size.height;
                if (lMaxPixels < lPixels) lMaxPixels = lPixels;
            }
            objs.add(lMaxPixels > 0 ? lMaxPixels : CONSTS.UNAVAILABLE);
        }
        di.Put(DeviceInfoKey.K.CA_PIXELS, objs);
    }
	
	private static void
	_PreviewFormat(DeviceInfo di, Camera.Parameters[] params)
    {
        //[[format1,format2],"unavailable"]
        ArrayList<Object> objs = new ArrayList<Object>(params.length);
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }
            
            List<Integer> formats;
            try {
                formats = param.getSupportedPreviewFormats();
            } catch (Exception e) { //java.lang.NullPointerException on emulator
                formats = null;
            }
            
            if (formats == null)
                objs.add(CONSTS.UNAVAILABLE);
            else {
                JSONArray array = new JSONArray(formats);
                objs.add(array);
            }
        }
        di.Put(DeviceInfoKey.K.CA_PV_FMT, objs);
    }
	
	private static void
    _PreviewSize(DeviceInfo di, Camera.Parameters[] params)
    {
        //[[[w1,h1],[w2,h2]],"unavailable"]
        ArrayList<Object> objs = new ArrayList<Object>(params.length);
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }

            List<Size> sizes = param.getSupportedPreviewSizes();
            if (sizes == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }

            JSONArray array = new JSONArray();
            for (Size size: sizes) {
                array.put(new JSONArray().put(size.width).put(size.height));
            }
            objs.add(array);
        }
        di.Put(DeviceInfoKey.K.CA_PV_SIZE, objs);
    }
	
	private static void
    _PreviewFrameRate(DeviceInfo di, Camera.Parameters[] params)
    {
        //[[rate1,rate2],"unavailable"]
        ArrayList<Object> objs = new ArrayList<Object>(params.length);
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }
            
            List<Integer> rates = param.getSupportedPreviewFrameRates();
            if (rates == null)
                objs.add(CONSTS.UNAVAILABLE);
            else {
                JSONArray array = new JSONArray(rates);
                objs.add(array);
            }
        }
        di.Put(DeviceInfoKey.K.CA_PV_FRATE, objs);
    }
	
	private static void
    _PreviewFPS(DeviceInfo di, Camera.Parameters[] params)
    {
        //[[[min1,max1],[main2,max2]],"unavailable"]
        ArrayList<Object> objs = new ArrayList<Object>(params.length);
        if (MiscUtil.GetSDKVersion() >= 9) {
            for (Camera.Parameters param: params) {
                if (param == null) {
                    objs.add(CONSTS.UNAVAILABLE);
                    continue;
                }
                
                List<int[]> frates = SDK9.GetInstance().CameraParameters_GetSupportedPreviewFpsRange(param);
                if (frates == null) {
                    objs.add(CONSTS.UNAVAILABLE);
                    continue;
                }
                
                JSONArray array = new JSONArray();
                for (int[] frate: frates) {
                    if (frate.length != 2) continue;
                    array.put(new JSONArray().put(frate[0]).put(frate[1]));
                }
                objs.add(array);
            }
        }
        else {
            for (int i = 0; i < params.length; i++) {
                objs.add(CONSTS.UNAVAILABLE);
            }
        }
        di.Put(DeviceInfoKey.K.CA_PV_FPS, objs);
    }
	
	private static void
    _VideoSize(DeviceInfo di, Camera.Parameters[] params)
    {
        //[[[w1,h1],[w2,h2]],"unavailable"]
        ArrayList<Object> objs = new ArrayList<Object>(params.length);
        if (MiscUtil.GetSDKVersion() >= 11) {
            for (Camera.Parameters param: params) {
                if (param == null) {
                    objs.add(CONSTS.UNAVAILABLE);
                    continue;
                }
    
                List<Size> sizes = SDK11.GetInstance().CameraParameters_GetSupportedVideoSizes(param);   
                if (sizes == null) {
                    objs.add(CONSTS.UNAVAILABLE);
                    continue;
                }
                
                JSONArray array = new JSONArray();
                for (Size size: sizes) {
                    array.put(new JSONArray().put(size.width).put(size.height));
                }
                objs.add(array);
            }
        }
        else {
            for (int i = 0; i < params.length; i++) {
                objs.add(CONSTS.UNAVAILABLE);
            }
        }
        di.Put(DeviceInfoKey.K.CA_VSIZE, objs);
    }
	
	private static void
    _ThumbnailSize(DeviceInfo di, Camera.Parameters[] params)
    {
        //[[[w1,h1],[w2,h2]],"unavailable"]
        ArrayList<Object> objs = new ArrayList<Object>(params.length);
        if (MiscUtil.GetSDKVersion() >= 8) {
            for (Camera.Parameters param: params) {
                if (param == null) {
                    objs.add(CONSTS.UNAVAILABLE);
                    continue;
                }
    
                List<Size> sizes = SDK8.GetInstance().CameraParameters_GetSupportedJpegThumbnailSizes(param); 
                if (sizes == null) {
                    objs.add(CONSTS.UNAVAILABLE);
                    continue;
                }
                
                JSONArray array = new JSONArray();
                for (Size size: sizes) {
                    array.put(new JSONArray().put(size.width).put(size.height));
                }
                objs.add(array);
            }
        }
        else {
            for (int i = 0; i < params.length; i++) {
                objs.add(CONSTS.UNAVAILABLE);
            }
        }
        di.Put(DeviceInfoKey.K.CA_THUMB_SIZE, objs);
    }
	
	private static void
    _Zoom(DeviceInfo di, Camera.Parameters[] params)
    {
        ArrayList<Object> objs = new ArrayList<Object>(params.length);
	    if (MiscUtil.GetSDKVersion() >= 8) {
	        SDK8 sdk8 = SDK8.GetInstance();
            //zoom
            //[true,"unavailable"]
            objs.clear();
            for (Camera.Parameters param: params) {
                if (param == null) {
                    objs.add(CONSTS.UNAVAILABLE);
                    continue;
                }
                objs.add(sdk8.CameraParameters_IsZoomSupported(param));
            }
            di.Put(DeviceInfoKey.K.CA_ZOOM, objs);
            
            //smooth zoom
            //[true,"unavailable"]
            objs.clear();
            for (Camera.Parameters param: params) {
                if (param == null) {
                    objs.add(CONSTS.UNAVAILABLE);
                    continue;
                }
                objs.add(sdk8.CameraParameters_IsSmoothZoomSupported(param));
            }
            di.Put(DeviceInfoKey.K.CA_SMOOTH_ZOOM, objs);
        }
	    else {
            for (int i = 0; i < params.length; i++) {
                objs.add(CONSTS.UNAVAILABLE);
            }
            di.Put(DeviceInfoKey.K.CA_ZOOM, objs);
            di.Put(DeviceInfoKey.K.CA_SMOOTH_ZOOM, objs);
        }
    }
	
	private static void
    _Others(DeviceInfo di, Camera.Parameters[] params)
    {
	    ArrayList<Object> objs = new ArrayList<Object>(params.length);
	    JSONArray array;
	    List<String> strVals;
	    
	    //Antibanding
	    //[[str1,str2],"unavailable"]
	    objs.clear();
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }
            strVals = param.getSupportedAntibanding();
            if (strVals == null) {
                objs.add(CONSTS.UNAVAILABLE);
            }
            else {
                array = new JSONArray(strVals);
                objs.add(array);
            }
        }
        di.Put(DeviceInfoKey.K.CA_ABAND, objs);
        
        //Color effects
        //[[str1,str2],"unavailable"]
        objs.clear();
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }
            strVals = param.getSupportedColorEffects();
            if (strVals == null) {
                objs.add(CONSTS.UNAVAILABLE);
            }
            else {
                array = new JSONArray(strVals);
                objs.add(array);
            }
        }
        di.Put(DeviceInfoKey.K.CA_CEFFECT, objs);
        
        //flash modes
        //[[str1,str2],"unavailable"]
        objs.clear();
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }
            strVals = param.getSupportedFlashModes();
            if (strVals == null) {
                objs.add(CONSTS.UNAVAILABLE);
            }
            else {
                array = new JSONArray(strVals);
                objs.add(array);
            }
        }
        di.Put(DeviceInfoKey.K.CA_FLASH, objs);
        
        //focus modes
        //[[str1,str2],"unavailable"]
        objs.clear();
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }
            
            strVals = param.getSupportedFocusModes();
            if (strVals == null) {
                objs.add(CONSTS.UNAVAILABLE);
            }
            else {
                array = new JSONArray(strVals);
                objs.add(array);
            }
        }
        di.Put(DeviceInfoKey.K.CA_FOCUS, objs);
        
        //scene modes
        //[[str1,str2],"unavailable"]
        objs.clear();
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }
            
            strVals = param.getSupportedSceneModes();
            if (strVals == null) {
                objs.add(CONSTS.UNAVAILABLE);
            }
            else {
                array = new JSONArray(strVals);
                objs.add(array);
            }
        }
        di.Put(DeviceInfoKey.K.CA_SCENE, objs);
        
        //white balance
        //[[str1,str2],"unavailable"]
        objs.clear();
        for (Camera.Parameters param: params) {
            if (param == null) {
                objs.add(CONSTS.UNAVAILABLE);
                continue;
            }
            
            strVals = param.getSupportedWhiteBalance();
            if (strVals == null) {
                objs.add(CONSTS.UNAVAILABLE);
            }
            else {
                array = new JSONArray(strVals);
                objs.add(array);
            }
        }
        di.Put(DeviceInfoKey.K.CA_WBAL, objs);
    }
}
